
#pragma once

namespace atr {
namespace core {
namespace __core {

/**
 * @brief   Make franction from value
 * @details Change 'Faction' value from integer to '0.Fraction'
 *
 * @tparam  T Type of output value
 * @tparam  Fraction value
 */
template <typename T, long Fraction>	struct __make_fraction;

/**
 * @brief   Make franction from value - terminator
 * @details Change 'Faction' value from integer to '0.Fraction'. This is the
 *  		case of zero value.
 *
 * @tparam  T Type of output value
 */
template <typename T>
struct __make_fraction<T, 0>
{
	/** How many position is there */
	static constexpr long base = 1;
	/** Output value */
	static constexpr T value = 0;
};

/**
 * @brief   Make franction from value - terminator
 * @details Change 'Faction' value from integer to '0.Fraction'. This is the
 *  		actual recurrect implementation.
 *
 * @tparam  T Type of output value
 * @tparam  Remaining fraction value
 */
template <typename T, long Fraction>
struct __make_fraction
{
	/** How many position is there */
	static constexpr long base = 10 * __make_fraction<T, Fraction / 10>::base;
	/** Output value */
	static constexpr T value = static_cast<T>(Fraction) / base;
};

template <typename T, long Integer, long Fraction, unsigned long Base>
struct __float
{
	/** Sign of Integer */
	static constexpr int  sgn      = Integer < 0 ? -1 : 1;
	/** Actual value of Integer */
	static constexpr long integer  = Integer;
	/** Actual value of Fraction */
	static constexpr long fraction = Fraction;
	/** Desired type of value */
	typedef T value_type;
	/** Metaprogramming type (e.g. atr::core::_float)*/
	typedef __float<T, Integer, Fraction, Base> type;
	/** Returns value of fraction in T type. Compiletype computation */
	constexpr operator T() const { return static_cast<T>(integer)
						   + sgn * __make_fraction<T, Fraction>::value / Base; }
};

} // namespace __core

template <long Integer, long Fraction, unsigned long Base = 1>
using _float  = __core::__float<float, Integer, Fraction, Base>;

template <long Integer, long Fraction, unsigned long Base = 1>
using _double  = __core::__float<double, Integer, Fraction, Base>;

} // namespace core
} // namespace atr